home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- ** **
- ** Module: PICTio.c **
- ** **
- ** **
- ** **
- ** Purpose: Read and write PICT files.
- **
- ** There are two different "read" routines.
- ** One uses QuickDraw, and so can draw any kind of PICT,
- ** but this only works on Macintoshes.
- **
- ** The other parses the PICT file directly, and only reads
- ** in a subset of the PICT opcodes, most particularly
- ** 24-32 bit images (DirectBitsRect). This works cross
- ** platform, at least on big-endian machines (it works on
- ** the SGI).
- **
- ** The "write" routine comes in only one version.
- ** Both Macintoshes and non-Macintoshes write out PICT
- ** files directly. One advantage to the interface is that
- ** images may be written out in a piecewise fashion,
- ** one scaline at a time. This is difficult if not
- ** impossible to do using the Macintosh toolbox. The
- ** incremental writing of an image is handy in particular
- ** when band-rendering or otherwise rendering on a machine
- ** with a small amount of memory compared with the
- ** rendering task.
- ** **
- ** **
- ** **
- ** Copyright (C) 1992-1995 Apple Computer, Inc. All rights reserved. **
- ** **
- ** **
- *****************************************************************************/
-
- #if defined(applec) || defined(THINK_C) || defined(__MWERKS__)
- # include <Quickdraw.h>
- # include <Memory.h>
- #endif /* defined(applec) || defined(THINK_C) || defined(__MWERKS__) */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include "QD3D.h"
- #include "PackBytes.h"
- #include "PICTio.h"
-
-
-
- #if defined(applec) || defined(THINK_C) || defined(__MWERKS__)
-
- /****************************************************************
- * Read PICT - Macintosh version.
- ****************************************************************/
-
- static FILE *PICTfd;
-
-
- /*===========================================================================*\
- *
- * Routine: GetPICTData()
- *
- * Comments: Bottleneck proc.
- *
- \*===========================================================================*/
-
- /* This is the replacement for the StdGetPic routine */
- static pascal void GetPICTData(
- Ptr dataPtr,
- short byteCount)
- {
- fread(dataPtr, 1, byteCount, PICTfd);
- }
-
- /*===========================================================================*\
- *
- * Routine: ErReadPICT()
- *
- * Comments: PICT reading
- *
- \*===========================================================================*/
-
- unsigned char *ErReadPICT( /* Returns a pointer to the baseAddr */
- long *width, /* Returns the width of the image */
- long *height, /* Returns the height of the image */
- long *rowBytes, /* Returns the rowBytes of the image */
- FILE *fd /* The I/O descriptor */
- )
- {
- unsigned char *image;
-
- CQDProcs myProcs;
- PicHandle myPicture;
- Rect pictR;
- CGrafPort myPort;
- GrafPtr savePort;
- PixMap *pm;
- GDHandle gd, saveGD;
-
- PICTfd = fd;
-
-
- /* Read the picture frame size */
- fseek(fd, 512L, 0);
- myPicture = (PicHandle)NewHandle(sizeof (Picture));
- HLock((Handle)myPicture);
- fread(*myPicture, sizeof(Picture), 1, fd);
- pictR = (*myPicture)->picFrame;
- HUnlock((Handle)myPicture);
-
- /* Allocate a bitmap */
- *width = pictR.right - pictR.left;
- *height = pictR.bottom - pictR.top;
- *rowBytes = (*width) * 4;
- if ((image = malloc((*rowBytes) * (*height))) == NULL) {
- fprintf(stderr, "Can't alloc image\n");
- return (NULL);
- }
-
- GetPort(&savePort);
-
- /* Allocate a GDevice */
- gd = NewGDevice(3, -1);
- (*gd)->gdType = 2;
- pm = *((*gd)->gdPMap);
- pm->rowBytes = 0x8000 | *rowBytes;
- pm->baseAddr = (Ptr)image;
- pm->bounds = pictR;
- pm->pixelType = 16;
- pm->pixelSize = 32;
- pm->cmpCount = 3;
- pm->cmpSize = 8;
- pm->pmTable = 0;
- (*gd)->gdRect = pictR;
- SetDeviceAttribute(gd, 0, 1);
- SetDeviceAttribute(gd, 11, 0);
- SetDeviceAttribute(gd, 13, 0);
- SetDeviceAttribute(gd, 14, 0);
- SetDeviceAttribute(gd, 15, 1);
-
- saveGD = GetGDevice();
- SetGDevice(gd);
-
- /* Allocate and initialize a CGrafPort */
- OpenCPort(&myPort);
- CopyPixMap((*gd)->gdPMap, myPort.portPixMap);
-
- /* Hack the visRgn */
- RectRgn(myPort.visRgn, &pictR);
-
- /* change the procs in the port */
- SetStdCProcs(&myProcs);
- #if defined(__MWERKS__) || defined(ppcinterfaces) || (THINK_C > 6)
- myProcs.getPicProc = NewQDGetPicProc(GetPICTData);
- #elif defined(THINK_C) && (THINK_C <= 6)
- myProcs.getPicProc = (Ptr)GetPICTData;
- #else
- myProcs.getPicProc = GetPICTData;
- #endif
- myPort.grafProcs = &myProcs;
-
- SetPort((GrafPtr)&myPort);
-
- DrawPicture(myPicture, &pictR);
-
- SetPort(savePort);
- SetGDevice(saveGD);
- CloseCPort(&myPort);
- DisposGDevice(gd);
-
- KillPicture(myPicture);
-
- return (image);
- }
-
- #else /* !macintosh */
-
-
- /****************************************************************
- * Read PICT - Non-Macintosh method: reading only 24-bit images.
- ****************************************************************/
-
- typedef char *Ptr;
- typedef long Fixed;
- typedef void **CTabHandle;
-
- typedef struct Rect {
- short top;
- short left;
- short bottom;
- short right;
- } Rect;
-
- typedef struct Picture {
- short picSize;
- Rect picFrame;
- } Picture;
-
- typedef struct PixMap {
- Ptr baseAddr; /*pointer to image*/
- short rowBytes; /*offset to next line*/
- Rect bounds; /*encloses bitmap*/
- short pmVersion; /*pixMap version number*/
- short packType; /*defines packing format*/
- long packSize; /*length of pixel data*/
- Fixed hRes; /*horiz. resolution (ppi)*/
- Fixed vRes; /*vert. resolution (ppi)*/
- short pixelType; /*defines pixel type*/
- short pixelSize; /*# bits in pixel*/
- short cmpCount; /*# components in pixel*/
- short cmpSize; /*# bits per component*/
- long planeBytes; /*offset to next plane*/
- CTabHandle pmTable; /*color map for this pixMap*/
- long pmReserved; /*for future use. MUST BE 0*/
- } PixMap;
-
-
- /*===========================================================================*\
- *
- * Routine: ErReadPICT()
- *
- * Comments: This reads only 24-bit images, but works on any machine.
- *
- \*===========================================================================*/
-
- unsigned char *ErReadPICT( /* Returns a pointer to the baseAddr */
- long *width, /* Returns the width of the image */
- long *height, /* Returns the height of the image */
- long *rowBytes, /* Returns the rowBytes of the image */
- FILE *f /* The I/O descriptor */
- )
- {
- unsigned char *image = NULL;
- Picture pictHeader; /* Assume that we like what it says */
- struct VersionBundle { short versionOpcode, version; } versionBundle;
- typedef struct { unsigned char a, r, g, b; } TColorI;
-
- fseek(f, 512L, 0); /* Skip 512 byte header */
-
- fread(&pictHeader, sizeof(pictHeader), 1, f);
-
- fread(&versionBundle, sizeof(versionBundle), 1, f);
- if (versionBundle.versionOpcode != 0x0011 || versionBundle.version != 0x02FF) {
- fprintf(stderr,
- "Bad version bundle: %04X %04X",
- versionBundle.versionOpcode,
- versionBundle.version);
- return (0);
- }
-
- for (;;) {
- short opCode;
- if (fread(&opCode, sizeof(opCode), 1, f) == 0)
- break;
- switch (opCode) {
- case 0x0000: /* NOP */
- break;
-
- case 0x0011: /* Version */
- {
- short version;
- fread(&version, sizeof(version), 1, f);
- if (version != 0x02FF) {
- fprintf(stderr, "Version %04X != 0x02FF", version);
- return (0);
- }
- } break;
-
- case 0x0C00: /* Header */
- {
- struct HeaderBundle {
- long sizeField; /* -1 */
- Fixed left;
- Fixed top;
- Fixed right;
- Fixed bottom;
- long appleReserved; /* 0 */
- } headerBundle;
- fread(&headerBundle, sizeof(headerBundle), 1, f);
- } break;
-
- case 0x001E: /* defHilite */
- break;
-
- case 0x0001: /* ClipRegion */
- {
- unsigned short clipRgnSize;
- fread(&clipRgnSize, sizeof(clipRgnSize), 1, f);
- fseek(f, (long)(clipRgnSize-2), 1); /* Skip clip region */
- } break;
-
- case 0x009A: /* directBitsRect */
- {
- struct ImageStuff {
- PixMap pixmap;
- Rect srcRect;
- Rect dstRect;
- short mode;
- } imageStuff;
-
- /* Get a buffer to hold the image */
- #if defined(applec) || defined(THINK_C)
- fread(&imageStuff, sizeof(imageStuff), 1, f);
- #else /* !macintosh */
- /* get around non-longword alignment */
- fread(&imageStuff.pixmap.baseAddr, sizeof(long), 1, f);
- fread(&imageStuff.pixmap.rowBytes, sizeof(short), 1, f);
- fread(&imageStuff.pixmap.bounds, sizeof(short), 4, f); /* left, top, right, bottom */
- fread(&imageStuff.pixmap.pmVersion, sizeof(short), 2, f); /* pmVersion, packType */
- fread(&imageStuff.pixmap.packSize, sizeof(long), 1, f);
- fread(&imageStuff.pixmap.hRes, sizeof(Fixed), 2, f); /* hRes, vRes */
- fread(&imageStuff.pixmap.pixelType, sizeof(short), 4, f); /* pixelType, pixelSize, cmpCount, cmpSize */
- fread(&imageStuff.pixmap.planeBytes, sizeof(long), 3, f); /* planeBytes, pmTable, pmReserved */
- fread(&imageStuff.srcRect, sizeof(short), 4, f); /* left, top, right, bottom */
- fread(&imageStuff.dstRect, sizeof(short), 4, f); /* left, top, right, bottom */
- fread(&imageStuff.mode, sizeof(short), 1, f);
- #endif /* macintosh */
-
- *width = imageStuff.srcRect.right - imageStuff.srcRect.left;
- *height = imageStuff.srcRect.bottom - imageStuff.srcRect.top;
- *rowBytes = 4 * (*width);
- image = malloc(*rowBytes * (*height));
-
- if (image != NULL) {
- char lineBuffer[5000]; /* scanline of components */
- char compLine[5000]; /* compressed scanline of components */
- register long i;
- int j;
- register char *p, *q;
- char *q0;
- int wordByteCount = (int)((imageStuff.pixmap.rowBytes & 0x3FFF) > 250); /* If byteCount is a word */
-
- for (q0 = (char *)image, j = *height; j--; q0 += *rowBytes) {
-
- /* Read a compressed scanline */
- if (wordByteCount) {
- unsigned short size;
- fread(&size, sizeof(size), 1, f);
- fread(compLine, size, 1, f);
- }
- else {
- unsigned char size;
- fread(&size, sizeof(size), 1, f);
- fread(compLine, size, 1, f);
- }
-
- /* Decompress the scanline */
- UnpackBytes(compLine, lineBuffer, 3*(*width));
-
- /* Interlace components into image */
- p = lineBuffer;
- for (i = *width, q = (char *)(&((TColorI*)q0)->r); i--; p++, q += sizeof(TColorI))
- *q = *p; /* Comb out red */
- for (i = *width, q = (char *)(&((TColorI*)q0)->g); i--; p++, q += sizeof(TColorI))
- *q = *p; /* Comb out green */
- for (i = *width, q = (char *)(&((TColorI*)q0)->b); i--; p++, q += sizeof(TColorI))
- *q = *p; /* Comb out blue */
- }
- if (ftell(f) & 1)
- getc(f);
- }
- else {
- fprintf(stderr, "Unable to allocate buffer(%d, %d) for ReadPICT", *width, *height);
- }
- } break;
-
- case 0x00FF: /* End opcode */
- return (image);
-
- default:
- fprintf(stderr, "Unknown opcode: %04X", opCode);
- return (image);
- }
- }
-
- return (NULL);
- }
-
- #endif /* !macintosh */
-
-
-
- typedef struct PICTheader {
- /* 512 bytes of 0's */
- Picture picture;
-
- short versionOpcode; /* 0x0011 */
- short version; /* 0x02FF */
-
- short headerOpcode; /* 0x0C00 */
- long sizeField; /* -1 */
- Fixed left;
- Fixed top;
- Fixed right;
- Fixed bottom;
- long appleReserved; /* 0 */
-
- short maxClipRegion[6]; /* 0001 000A 8001 8001 7FFF 7FFF */
-
- short directBitsRect; /* 009A */
- PixMap pixmap;
- Rect srcRect;
- Rect dstRect;
- short mode;
- /* PixelData */
- } PICTHeader;
-
-
- /*===========================================================================*\
- *
- * Routine: StartWritePICT()
- *
- * Comments: Write header for a 24-bit PICT file without using QuickDraw.
- *
- \*===========================================================================*/
-
- long StartWritePICT(
- long width,
- long height,
- FILE *f
- )
- {
- struct PICTheader myPICTheader;
-
- { /* Write out the 512 byte header pad */
- long headPad[512/sizeof(long)];
- register long *lp = headPad;
- register int i;
- char *cHeadPad = (char *)headPad;
-
- for (i = 512/sizeof(long); i--; *lp++ = 0) {
- /* do nothing */ ; /* Clear header pad */
- }
-
- cHeadPad[0] = 'P'; /* Record the type of the file */
- cHeadPad[1] = 'I';
- cHeadPad[2] = 'C';
- cHeadPad[3] = 'T';
-
- fwrite(cHeadPad, 1, 512, f); /* Write out the header pad */
- }
-
- /* Make SURE the size of the image is adequately recorded */
- myPICTheader.picture.picSize = 0;
- myPICTheader.picture.picFrame.top = 0;
- myPICTheader.picture.picFrame.left = 0;
- myPICTheader.picture.picFrame.bottom = height;
- myPICTheader.picture.picFrame.right = width;
- myPICTheader.versionOpcode = 0x0011;
- myPICTheader.version = 0x02FF; /* Version 2 */
- myPICTheader.headerOpcode = 0x0C00;
- myPICTheader.sizeField = -1;
- myPICTheader.left = 0;
- myPICTheader.top = 0;
- myPICTheader.right = width << 16;
- myPICTheader.bottom = height << 16;
- myPICTheader.appleReserved = 0;
- myPICTheader.maxClipRegion[0] = 0x0001; /* Clip region opcode */
- myPICTheader.maxClipRegion[1] = 0x000A; /* sizeof (Rect) + 2 */
- myPICTheader.maxClipRegion[2] = 0x8001; /* top */
- myPICTheader.maxClipRegion[3] = 0x8001; /* left */
- myPICTheader.maxClipRegion[4] = 0x7FFF; /* bottom */
- myPICTheader.maxClipRegion[5] = 0x7FFF; /* right */
- myPICTheader.directBitsRect = 0x009A;
- myPICTheader.pixmap.baseAddr = (Ptr)0x000000FF;
- myPICTheader.pixmap.rowBytes = (4 * width) | 0x8000;
- myPICTheader.pixmap.bounds.top = 0;
- myPICTheader.pixmap.bounds.left = 0;
- myPICTheader.pixmap.bounds.bottom = height;
- myPICTheader.pixmap.bounds.right = width;
- myPICTheader.pixmap.pmVersion = 0;
- myPICTheader.pixmap.packType = 4;
- myPICTheader.pixmap.packSize = 0;
- myPICTheader.pixmap.hRes = 72 << 16;
- myPICTheader.pixmap.vRes = 72 << 16;
- myPICTheader.pixmap.pixelType = 16;
- myPICTheader.pixmap.pixelSize = 32;
- myPICTheader.pixmap.cmpCount = 3;
- myPICTheader.pixmap.cmpSize = 8;
- myPICTheader.pixmap.planeBytes = 0;
- myPICTheader.pixmap.pmTable = 0;
- myPICTheader.pixmap.pmReserved = 0;
- myPICTheader.srcRect.top = 0;
- myPICTheader.srcRect.left = 0;
- myPICTheader.srcRect.bottom = height;
- myPICTheader.srcRect.right = width;
- myPICTheader.dstRect.top = 0;
- myPICTheader.dstRect.left = 0;
- myPICTheader.dstRect.bottom = height;
- myPICTheader.dstRect.right = width;
- myPICTheader.mode = 0x0040; /* Dither */
-
- #if defined(applec) || defined(THINK_C)
- fwrite(&myPICTheader, sizeof(myPICTheader), 1, f);
- #else /* !macintosh, but not for the Cray */
- fwrite(&myPICTheader.picture.picSize, sizeof(short), 1, f);
- fwrite(&myPICTheader.picture.picFrame, sizeof(short), 4, f); /* left, top, right, bottom */
-
- fwrite(&myPICTheader.versionOpcode, sizeof(short), 2, f); /* versionOpCode, version */
-
- fwrite(&myPICTheader.headerOpcode, sizeof(short), 1, f);
- fwrite(&myPICTheader.sizeField, sizeof(long), 1, f);
- fwrite(&myPICTheader.left, sizeof(Fixed), 4, f); /* left, top, right, bottom */
- fwrite(&myPICTheader.appleReserved, sizeof(long), 1, f);
-
- fwrite(myPICTheader.maxClipRegion, sizeof(short), 6, f);
-
- fwrite(&myPICTheader.directBitsRect, sizeof(short), 1, f);
- fwrite(&myPICTheader.pixmap.baseAddr, sizeof(long), 1, f);
- fwrite(&myPICTheader.pixmap.rowBytes, sizeof(short), 1, f);
- fwrite(&myPICTheader.pixmap.bounds, sizeof(short), 4, f); /* left, top, right, bottom */
- fwrite(&myPICTheader.pixmap.pmVersion, sizeof(short), 2, f); /* pmVersion, packType */
- fwrite(&myPICTheader.pixmap.packSize, sizeof(long), 1, f);
- fwrite(&myPICTheader.pixmap.hRes, sizeof(Fixed), 2, f); /* hRes, vRes */
- fwrite(&myPICTheader.pixmap.pixelType, sizeof(short), 4, f); /* pixelType, pixelSize, cmpCount, cmpSize */
- fwrite(&myPICTheader.pixmap.planeBytes, sizeof(long), 3, f); /* planeBytes, pmTable, pmReserved */
- fwrite(&myPICTheader.srcRect, sizeof(short), 4, f); /* left, top, right, bottom */
- fwrite(&myPICTheader.dstRect, sizeof(short), 4, f); /* left, top, right, bottom */
- fwrite(&myPICTheader.mode, sizeof(short), 1, f);
- #endif /* macintosh */
-
- return (!ferror(f)); /* 1 if no error, 0 otherwise */
- }
-
-
-
- /*===========================================================================*\
- *
- * Routine: WritePICTLines()
- *
- * Comments: Write the specified number of lines.
- *
- \*===========================================================================*/
-
- long WritePICTLines(
- unsigned char *buf,
- long width,
- long height,
- long rowBytes,
- FILE *f
- )
- {
- unsigned char lineBuffer[5200]; /* scanline of components */
- unsigned char compLine[5200]; /* compressed scanline of components */
- register int i;
- int wordByteCount;
- register unsigned char *p, *q;
- unsigned char *q0;
-
- wordByteCount = (int)(width > 250/4); /* If byteCount is a word */
-
- for (q0 = buf; height--; q0 += rowBytes) {
-
- /* Comb components out of image */
- p = lineBuffer;
- for (i = width, q = q0 + 1; i--; p++, q += 4)
- *p = *q; /* Comb out red */
- for (i = width, q = q0 + 2; i--; p++, q += 4)
- *p = *q; /* Comb out green */
- for (i = width, q = q0 + 3; i--; p++, q += 4)
- *p = *q; /* Comb out blue */
-
- /* Write out the size of this compressed scanline */
- i = (int)PackBytes((char *)lineBuffer, (char *)compLine, 3*width);
- if (wordByteCount) {
- unsigned char size[2];
- size[0] = (unsigned char)(i >> 8);
- size[1] = (unsigned char)i;
- fwrite(size, 2, 1, f);
- }
- else {
- unsigned char size = i;
- fwrite(&size, 1, 1, f);
- }
-
- /* Write out the compressed scanline */
- fwrite(compLine, 1, i, f);
- }
-
- return (!ferror(f)); /* 1 if no error, 0 otherwise */
- }
-
-
- /*===========================================================================*\
- *
- * Routine: EndWritePICT()
- *
- * Comments: Close up PICT file.
- *
- \*===========================================================================*/
-
- long EndWritePICT(
- FILE *f
- )
- {
- short code;
-
- /* Write end opcode */
- if (ftell(f) & 1) putc(0, f); /* Make sure we are word aligned */
- code = 0x00FF;
- fwrite(&code, sizeof(short), 1, f);
-
- /* Backfit picSize */
- code = (short)(ftell(f) - 512L);
- fseek(f, 512L, 0);
- fwrite(&code, 2, 1, f);
-
- return (!ferror(f)); /* 1 if no error, 0 otherwise */
- }
-
-
- /*===========================================================================*\
- *
- * Routine: ErWritePICT()
- *
- * Comments: Write a PICT file.
- *
- \*===========================================================================*/
-
- long ErWritePICT(
- unsigned char *baseAddr,
- long width,
- long height,
- long rowBytes,
- FILE *f
- )
- {
- if (height < 0) {
- height = -height;
- /* This takes care of the case when Y goes up; rowBytes should be < 0 */
- }
-
- StartWritePICT(width, height, f);
- WritePICTLines(baseAddr, width, height, rowBytes, f);
- EndWritePICT(f);
-
- return (!ferror(f)); /* 1 if no error, 0 otherwise */
- }
-
-